package com.blyat.xsoft.kernel.component.security.oauth2.token.jwt;

import com.blyat.xsoft.kernel.component.security.oauth2.OauthConstant;
import com.blyat.xsoft.kernel.component.security.oauth2.token.AbstractTokenRefreshExecutor;
import com.blyat.xsoft.kernel.component.security.oauth2.util.TokenUtil;
import com.blyat.xsoft.kernel.util.HttpUtil;
import com.blyat.xsoft.kernel.util.ServletUtil;
import com.google.common.base.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @Auther: syh
 * @Date: 2020/7/22
 * @Description:
 */
public class OauthJwtTokenRefreshExecutor extends AbstractTokenRefreshExecutor {

    private static final Logger logger = LoggerFactory.getLogger(OauthJwtTokenRefreshExecutor.class);

    @Override
    public boolean shouldRefresh() {
        // 旧token过期才刷新
        return getAccessToken() != null && getAccessToken().isExpired();
    }

    @Override
    public String refresh() throws Exception {
        HttpServletRequest request = ServletUtil.getRequest();
        HttpServletResponse response = ServletUtil.getResponse();
        Map<String, Object> parameters = new LinkedHashMap<>();
        // OauthJwtAccessTokenConverter中存入access_token中的数据，在这里使用
        parameters.put("client_id", TokenUtil.decryptInfo(getAccessToken(), OauthConstant.OAUTH_CLIENT_ID));
        parameters.put("client_secret", TokenUtil.decryptInfo(getAccessToken(), OauthConstant.OAUTH_CLIENT_SECRET));
        parameters.put("refresh_token", TokenUtil.decryptInfo(getAccessToken(), OauthConstant.OAUTH_REFRESH_TOKEN));
        parameters.put("grant_type", "refresh_token");
        // 发送刷新的http请求
        Map<String, Object> result = HttpUtil.post(getOauthTokenUrl(request), parameters);

        if (Objects.isNull(result) || result.size() <= 0 || !result.containsKey("access_token")) {
            throw new IllegalStateException("refresh token failed.");
        }

        String accessToken = result.get("access_token").toString();
        OAuth2AccessToken oAuth2AccessToken = getTokenStore().readAccessToken(accessToken);
        OAuth2Authentication auth2Authentication = getTokenStore().readAuthentication(oAuth2AccessToken);
        // 保存授权信息，以便全局调用
        SecurityContextHolder.getContext().setAuthentication(auth2Authentication);

        // 前端收到该event事件时，更新access_token
        response.setHeader("event", "token-refreshed");
        response.setHeader("access_token", accessToken);
        // 返回新的token信息
        return accessToken;
    }

    private String getOauthTokenUrl(HttpServletRequest request) {
        return String.format("%s://%s:%s%s%s",
                request.getScheme(),
                request.getLocalAddr(),
                request.getLocalPort(),
                !Strings.isNullOrEmpty(request.getContextPath()) ? "/" + request.getContextPath() : "",
                "/oauth/token");
    }
}
